package edu.ec.tesis.prototiporecomendador.ngc.Recomendadores.Semantico;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import edu.ec.tesis.prototiporecomendador.mdl.Item;
import edu.ec.tesis.prototiporecomendador.mdl.User;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.Calificacion;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.Configuration;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.NearestNeighbors;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.NoExisteLaOntologiaException;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.NoSePudoPersistirElModeloException;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.UserDataFileReader;
import edu.ec.tesis.prototiporecomendador.ngc.UserProfile.UserOntologyManager;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RecomendadorSemantico {

    /**
     * Metodo que obtiene las predicciones de los DOI de los contenidos de test,
     * utilizando la informacion de la dispercion de los DOI por las
     * caracteristicas semanticas de los contenidos formalizado en el
     * perfil-ontolgia de usuario
     */
    public static void recomendarPorDispersion() {
        try {
            Configuration conf = Configuration.getInstance();
            System.out.println("Recomendacion por dispersion...");
            //creo el archivo de salida
            FileWriter f1 = new FileWriter(conf.getOUTRECOMMENDATION() + "dispersion.txt");
            BufferedWriter b1 = new BufferedWriter(f1);
            float error = 0, nratings = 0;
            //obtengo las calificaciones que se quieren predecir agrupadas por usuario
            ArrayList<ArrayList<Calificacion>> agrupados = UserDataFileReader.RatingsReadLines(conf.getDBTEST());
            Iterator<ArrayList<Calificacion>> ite = agrupados.iterator();

            //recorro los usuarios
            while (ite.hasNext()) {
                ArrayList<Calificacion> grupo = ite.next();

                if (!grupo.isEmpty()) {
                    System.out.println(grupo.get(0).getIdUser());

                    //obtengo el perfil-ontolgia del usuario
                    OntModel movies = UserOntologyManager.getMovieModel(conf);
                    OntModel user = UserOntologyManager.getUserModel(grupo.get(0).getIdUser(), conf);
                    double errorUsuario = 0;
                    double numCalfsUsuario = 0;
                    Iterator<Calificacion> ite2 = grupo.iterator();

                    //recorro las peliculas a las que voy a comparar la calificacion real con la predicha
                    while (ite2.hasNext()) {
                        Calificacion cal = ite2.next();
                        //obtengo el id de la pelicula en IMDb
                        String IMDbMovieID = UserOntologyManager.getMovieID(cal.getIdMovie(), conf.getDBMOVIES());
                        //obtengo la instancia de la pelicula en la ontologia
                        Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);

                        if (movie != null) {

                            float inferedDOI = 0;
                            int generalcount = 0;

                            //obtengo sus generos, actores, directores, escritores
                            Property hasActor = movies.getProperty(conf.getNS() + "hasActor"); //propiedad que necesito								
                            Property hasDirector = movies.getProperty(conf.getNS() + "hasDirector");
                            Property hasWriter = movies.getProperty(conf.getNS() + "hasWriter");

                            //recorro las propiedades y obtengo las instancias relacionadas
                            float actorsDOI = doiPropierty(user, movie, hasActor);
                            float directorsDOI = doiPropierty(user, movie, hasDirector);
                            float writerDOI = doiPropierty(user, movie, hasWriter);
                            float genresDOI = doiGenres(movies, movie, grupo.get(0).getIdUser(), conf, true);
                            if (actorsDOI != 0) {
                                generalcount++;
                            }
                            if (directorsDOI != 0) {
                                generalcount++;
                            }
                            if (writerDOI != 0) {
                                generalcount++;
                            }
                            if (genresDOI != 0) {
                                generalcount++;
                            }

                            if (generalcount != 0) {
                                inferedDOI = (actorsDOI + directorsDOI + writerDOI + genresDOI) / generalcount;
                            }

                            //inferedDOI = ponderarConRantingIMDb(movies, movie, inferedDOI, conf);
                            //guardo el DOI predicho en el archivo de salida
                            error = error + Math.abs(inferedDOI - (int) cal.getRating());
                            errorUsuario += Math.abs(inferedDOI - (int) cal.getRating());
                            numCalfsUsuario++;
                            nratings = nratings + 1;
                        } else {
                            System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                        }
                    }
                    String linea = grupo.get(0).getIdUser() + "::" + errorUsuario / numCalfsUsuario / 5d;

                    System.out.println(linea + "\nel error es: " + errorUsuario / numCalfsUsuario / 5d);
                    b1.write(linea);
                    b1.newLine();
                    b1.flush();
                }
            }

            System.err.println("el error total es: " + (error / nratings) / 5);
            b1.close();
        } catch (NoExisteLaOntologiaException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSePudoPersistirElModeloException e) {
            e.printStackTrace();
        }
    }

    public double obtenValoracion(int idUser, int idMovie) {
        double valoracion = 0;
        Configuration conf = Configuration.getInstance();
        try {
            OntModel movies = UserOntologyManager.getMovieModel(conf);
            OntModel user = UserOntologyManager.getUserModel(idUser, conf);
            String IMDbMovieID = UserOntologyManager.getMovieID(idMovie, conf.getDBMOVIES());

            //obtengo la instancia de la pelicula en la ontologia
            Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);
            // user.get
            if (movie != null) {

                Individual movieU = user.getIndividual(conf.getNS() + IMDbMovieID);
                if (movieU == null) {
                    OntModel aux = movie.getOntModel();
                    user.add(aux);
                }

                //obtengo las secuencias de propiedades relevantes para el usuario
                ArrayList<PropertySequence> sequence = Filtrado.filtradoDePropiedades(user, movie);
                // System.out.println("Inferiendo");
                //obtengo el DOI predicho

                double inferedDOI = Inferencia.inferedDOI(user, sequence, movie, idUser, conf, true);

                return inferedDOI;					//pondero el DOI predicho con el rating otorgado por IMDb
                //inferedDOI = ponderarConRantingIMDb(user, movie, inferedDOI, conf);
                //guardo el DOI predicho en el archivo de salida

            } else {
                System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                return 0;
            }
        } catch (NoSePudoPersistirElModeloException ex) {
            Logger.getLogger(RecomendadorSemantico.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoExisteLaOntologiaException ex) {
            Logger.getLogger(RecomendadorSemantico.class.getName()).log(Level.SEVERE, null, ex);
        }

        return valoracion;
    }

    public double obtenValoracionDispercion(int idUser, int idMovie) {
        double valoracion = 0;
        Configuration conf = Configuration.getInstance();
        try {
            OntModel movies = UserOntologyManager.getMovieModel(conf);
            OntModel user = UserOntologyManager.getUserModel(idUser, conf);
            String IMDbMovieID = UserOntologyManager.getMovieID(idMovie, conf.getDBMOVIES());

            //obtengo la instancia de la pelicula en la ontologia
            Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);
            // user.get
            if (movie != null) {

                float inferedDOI = 0;
                int generalcount = 0;

                //obtengo sus generos, actores, directores, escritores
                Property hasActor = movies.getProperty(conf.getNS() + "hasActor"); //propiedad que necesito								
                Property hasDirector = movies.getProperty(conf.getNS() + "hasDirector");
                Property hasWriter = movies.getProperty(conf.getNS() + "hasWriter");

                //recorro las propiedades y obtengo las instancias relacionadas
                float actorsDOI = doiPropierty(user, movie, hasActor);
                float directorsDOI = doiPropierty(user, movie, hasDirector);
                float writerDOI = doiPropierty(user, movie, hasWriter);
                float genresDOI = doiGenres(movies, movie, idUser, conf, true);
                if (actorsDOI != 0) {
                    generalcount++;
                }
                if (directorsDOI != 0) {
                    generalcount++;
                }
                if (writerDOI != 0) {
                    generalcount++;
                }
                if (genresDOI != 0) {
                    generalcount++;
                }

                if (generalcount != 0) {
                    inferedDOI = (actorsDOI + directorsDOI + writerDOI + genresDOI) / generalcount;
                }
                return inferedDOI;
            } else {
                System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                return 0;
            }
        } catch (NoSePudoPersistirElModeloException ex) {
            Logger.getLogger(RecomendadorSemantico.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoExisteLaOntologiaException ex) {
            Logger.getLogger(RecomendadorSemantico.class.getName()).log(Level.SEVERE, null, ex);
        }

        return valoracion;
    }

    public List<Item> generarRecomendaciones(int idUser, List<Item> items, int numRec, int algoritmo) {
        for (Item item : items) {
            if (algoritmo == 0) {
                System.out.println("Recomendando por Inferencia");
                item.setValoracion(obtenValoracion(idUser, item.getItemId()));
            } else if (algoritmo == 1) {
                System.out.println("Recomendando por Dispersion");
                item.setValoracion(obtenValoracionDispercion(idUser, item.getItemId()));
            }
        }

        for (int i = 0; i < items.size(); i++) {
            for (int j = i; j < items.size(); j++) {
                if (items.get(j).getValoracion() > items.get(i).getValoracion()) {
                    //Item aux = (Item)items.get(i).clone();
                    Item aux = new Item();
                    aux.setIdIMDB(items.get(i).getIdIMDB());
                    aux.setIntemDesc(items.get(i).getIntemDesc());
                    aux.setIntemGenre(items.get(i).getIntemGenre());
                    aux.setItemActores(items.get(i).getItemActores());
                    aux.setItemId(items.get(i).getItemId());
                    aux.setRating(items.get(i).getRating());
                    aux.setValoracion(items.get(i).getValoracion());

                    items.get(i).setIdIMDB(items.get(j).getIdIMDB());
                    items.get(i).setIntemDesc(items.get(j).getIntemDesc());
                    items.get(i).setIntemGenre(items.get(j).getIntemGenre());
                    items.get(i).setItemActores(items.get(j).getItemActores());
                    items.get(i).setItemId(items.get(j).getItemId());
                    items.get(i).setRating(items.get(j).getRating());
                    items.get(i).setValoracion(items.get(j).getValoracion());

                    items.get(j).setIdIMDB(aux.getIdIMDB());
                    items.get(j).setIntemDesc(aux.getIntemDesc());
                    items.get(j).setIntemGenre(aux.getIntemGenre());
                    items.get(j).setItemActores(aux.getItemActores());
                    items.get(j).setItemId(aux.getItemId());
                    items.get(j).setRating(aux.getRating());
                    items.get(j).setValoracion(aux.getValoracion());
                }
            }
        }
        if (items.size() > numRec) {
            for (int i = items.size() - 1; i >= numRec; i--) {
                items.remove(i);
            }
        }
        System.out.println("listo");
        return items;
    }

    public static double recomendarConSecuencia() {
        try {
            Configuration conf = Configuration.getInstance();

            //creo el archivo de salida que contendra las predicciones de los DOI
            FileWriter f1 = new FileWriter(conf.getOUTRECOMMENDATION() + "inferencia.txt");
            BufferedWriter b1 = new BufferedWriter(f1);
            double error = 0, errorTotal = 0, errorUsuario = 0, contadorUsuario = 0, contadorTotal = 0;
            //obtengo las calificaciones que se quieren predecir agrupadas por usuario
            ArrayList<ArrayList<Calificacion>> agrupados = UserDataFileReader.RatingsReadLines(conf.getDBTEST());
            Iterator<ArrayList<Calificacion>> ite = agrupados.iterator();

            //recorro los usuarios
            OntModel movies = UserOntologyManager.getMovieModel(conf);
            while (ite.hasNext()) {
                ArrayList<Calificacion> grupo = ite.next();
                if (!grupo.isEmpty()) {
                    System.out.println(grupo.get(0).getIdUser());

                    //obtengo el perfil-ontolgia del usuario
                    OntModel user = UserOntologyManager.getUserModel(grupo.get(0).getIdUser(), conf);
                    Iterator<Calificacion> ite2 = grupo.iterator();

                    //recorro las peliculas calificadas a las que predecir el DOI, para luego compararlo con la calificacion real.
                    errorUsuario = 0;
                    contadorUsuario = 0;
                    while (ite2.hasNext()) {
                        Calificacion cal = ite2.next();

                        //obtengo el id de la pelicula en IMDb
                        String IMDbMovieID = UserOntologyManager.getMovieID(cal.getIdMovie(), conf.getDBMOVIES());

                        //obtengo la instancia de la pelicula en la ontologia
                        Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);
                        // user.get
                        if (movie != null) {

                            Individual movieU = user.getIndividual(conf.getNS() + IMDbMovieID);
                            if (movieU == null) {
                                OntModel aux = movie.getOntModel();
                                user.add(aux);
                            }

                            //obtengo las secuencias de propiedades relevantes para el usuario
                            ArrayList<PropertySequence> sequence = Filtrado.filtradoDePropiedades(user, movie);
                            // System.out.println("Inferiendo");
                            //obtengo el DOI predicho

                            double inferedDOI = Inferencia.inferedDOI(user, sequence, movie, grupo.get(0).getIdUser(), conf, true);

                            //pondero el DOI predicho con el rating otorgado por IMDb
                            //inferedDOI = ponderarConRantingIMDb(user, movie, inferedDOI, conf);
                            //guardo el DOI predicho en el archivo de salida
                            String linea = cal.getIdUser() + "," + cal.getIdMovie() + "," + inferedDOI + "," + cal.getRating();
                            error = Math.abs(inferedDOI - cal.getRating());
                            errorUsuario += error;
                            errorTotal += error;
                            contadorUsuario++;
                            contadorTotal++;

                        } else {
                            System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                        }

                    }
                    String linea = grupo.get(0).getIdUser() + "::" + ((errorUsuario / contadorUsuario) / 5d);
                    b1.write(linea);
                    b1.newLine();
                    b1.flush();
                }
            }
            String linea = "errorPromedioTotal" + "::" + ((errorTotal / contadorTotal) / 5);
            b1.write(linea);
            b1.newLine();
            b1.flush();
            b1.close();
            return ((errorTotal / contadorTotal) / 5);
        } catch (NoExisteLaOntologiaException e) {
            e.printStackTrace();
            return 0;
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        } catch (NoSePudoPersistirElModeloException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public static double recomendarConSecuenciaEstereotipo() {
        try {
            Configuration conf = Configuration.getInstance();

            //creo el archivo de salida que contendra las predicciones de los DOI
            FileWriter f1 = new FileWriter(conf.getOUTRECOMMENDATION() + "Estereoptipos.dat");
            BufferedWriter b1 = new BufferedWriter(f1);
            double error = 0, errorTotal = 0, errorUsuario = 0, contadorUsuario = 0, contadorTotal = 0;
            //obtengo las calificaciones que se quieren predecir agrupadas por usuario
            ArrayList<ArrayList<Calificacion>> agrupados = UserDataFileReader.RatingsReadLines(conf.getDBTEST());
            Iterator<ArrayList<Calificacion>> ite = agrupados.iterator();

            //recorro los usuarios
            while (ite.hasNext()) {
                ArrayList<Calificacion> grupo = ite.next();
                if (!grupo.isEmpty()) {
                    System.out.println(grupo.get(0).getIdUser());

                    //obtengo el perfil-ontolgia del estereotipo
                    int idEstereotipo = buscaEstereotipo(grupo.get(0).getIdUser());

                    OntModel estereotype = UserOntologyManager.getStereotypeModel(idEstereotipo, conf);
                    OntModel movies = UserOntologyManager.getMovieModel(conf);
                    Iterator<Calificacion> ite2 = grupo.iterator();

                    //recorro las peliculas calificadas a las que predecir el DOI, para luego compararlo con la calificacion real.
                    errorUsuario = 0;
                    contadorUsuario = 0;
                    while (ite2.hasNext()) {
                        Calificacion cal = ite2.next();

                        //obtengo el id de la pelicula en IMDb
                        String IMDbMovieID = UserOntologyManager.getMovieID(cal.getIdMovie(), conf.getDBMOVIES());

                        //obtengo la instancia de la pelicula en la ontologia
                        Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);
                        // user.get
                        if (movie != null) {
                            //obtengo las secuencias de propiedades relevantes para el usuario
                            ArrayList<PropertySequence> sequence = Filtrado.filtradoDePropiedades(estereotype, movie);
                            // System.out.println("Inferiendo");
                            //obtengo el DOI predicho
                            double inferedDOI = Inferencia.inferedDOI(estereotype, sequence, movie, idEstereotipo, conf, false);

                            //pondero el DOI predicho con el rating otorgado por IMDb
                            //inferedDOI = ponderarConRantingIMDb(user, movie, inferedDOI, conf);
                            //guardo el DOI predicho en el archivo de salida
                            String linea = cal.getIdUser() + "," + cal.getIdMovie() + "," + inferedDOI + "," + cal.getRating();
                            error = Math.abs(inferedDOI - cal.getRating());
                            errorUsuario += error;
                            errorTotal += error;
                            contadorUsuario++;
                            contadorTotal++;

                        } else {
                            System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                        }

                    }
                    String linea = grupo.get(0).getIdUser() + "::" + ((errorUsuario / contadorUsuario) / 5d);
                    b1.write(linea);
                    b1.newLine();
                    b1.flush();
                }
            }
            String linea = "errorPromedioTotal" + "::" + ((errorTotal / contadorTotal) / 5);
            b1.write(linea);
            b1.newLine();
            b1.flush();
            b1.close();
            return ((errorTotal / contadorTotal) / 5);
        } catch (NoExisteLaOntologiaException e) {
            e.printStackTrace();
            return 0;
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        } catch (NoSePudoPersistirElModeloException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public static void recomendarUser(int id) {
        try {
            Configuration conf = Configuration.getInstance();
            System.out.println("Recomendacion para el usuario" + id + "...");
            //creo el archivo de salida
            FileWriter f1 = new FileWriter(conf.getOUTRECOMMENDATION() + "Usuario" + id + ".dat");
            BufferedWriter b1 = new BufferedWriter(f1);
            //obtengo la lista de peliculas definidas en DBMOVIES (base de peliculas)
            ArrayList<String> dbMovies = UserDataFileReader.readLines(conf.getDBMOVIES());
            ArrayList<String> recomendation = new ArrayList<String>();

            //obtengo el perfil-ontolgia del usuario
            OntModel movies = UserOntologyManager.getMovieModel(conf);
            OntModel user = UserOntologyManager.getUserModel(id, conf);
            //recorro las peliculas a las que voy a predecir
            int count = 0;
            while (dbMovies.size() >= count) {
                count++;
                //obtengo el id de la pelicula en IMDb
                String IMDbMovieID = UserOntologyManager.getMovieID(count, conf.getDBMOVIES());
                //obtengo la instancia de la pelicula en la ontologia
                Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);

                if (movie != null) {

                    double inferedDOI = 0;
                    int generalcount = 0;

                    //obtengo sus generos, actores, directores, escritores
                    Property hasActor = movies.getProperty(conf.getNS() + "hasActor"); //propiedad que necesito								
                    Property hasDirector = movies.getProperty(conf.getNS() + "hasDirector");
                    Property hasWriter = movies.getProperty(conf.getNS() + "hasWriter");

                    //recorro las propiedades y obtengo las instancias relacionadas
                    double actorsDOI = doiPropierty(user, movie, hasActor) * conf.getwActors();
                    double directorsDOI = doiPropierty(user, movie, hasDirector) * conf.getwDirectors();
                    double writerDOI = doiPropierty(user, movie, hasWriter) * conf.getwWirters();
                    double genresDOI = doiGenres(movies, movie, id, conf, true) * conf.getwGenres();
                    if (actorsDOI != 0) {
                        generalcount++;
                    }
                    if (directorsDOI != 0) {
                        generalcount++;
                    }
                    if (writerDOI != 0) {
                        generalcount++;
                    }
                    if (genresDOI != 0) {
                        generalcount++;
                    }

                    if (generalcount != 0) {
                        inferedDOI = (actorsDOI + directorsDOI + writerDOI + genresDOI) / generalcount;
                        System.err.println(actorsDOI + "   " + directorsDOI + "   " + writerDOI + "   " + genresDOI + " = " + inferedDOI);
                    }

                    //inferedDOI = ponderarConRantingIMDb(movies, movie, inferedDOI, conf);
                    //guardo el DOI predicho en el archivo de salida
                    String linea = id + "," + count + "," + inferedDOI + "," + movie;
                    recomendation.add(linea);
                    if (count > 100) {
                        break;
                    }

                } else {
                    System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                }
            }
            recomendation = top(recomendation, recomendation.size());
            count = 0;
            while (recomendation.size() > (count)) {
                b1.write(recomendation.get(count));
                b1.newLine();
                b1.flush();
                count++;
            }

            b1.close();
        } catch (NoExisteLaOntologiaException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSePudoPersistirElModeloException e) {
            e.printStackTrace();
        }
    }

    public static void recomedarPorNN(String par) {
        try {
            Configuration conf = Configuration.getInstance();
            System.out.println("Recomendacion por NearestNeightbors...(error)");
            //creo el archivo de salida
            FileWriter f1 = new FileWriter("RecomendacionPorNN" + par + ".dat");
            BufferedWriter b1 = new BufferedWriter(f1);
            float error = 0, nratings = 0, countU = 0;
            //obtengo las calificaciones que se quieren predecir agrupadas por usuario
            ArrayList<ArrayList<Calificacion>> agrupados = UserDataFileReader.RatingsReadLines(conf.getDBTEST());
            Iterator<ArrayList<Calificacion>> ite = agrupados.iterator();
            //recorro los usuarios
            OntModel movies = UserOntologyManager.getMovieModel(conf);
            while (ite.hasNext()) {
                ArrayList<Calificacion> grupo = ite.next();
                float Uerror = 0, Unratings = 0;

                if (!grupo.isEmpty()) {
                    countU++;
                    //obtengo el perfil-ontolgia del usuario
                    int flag = 0;
                    ArrayList<String> nn = NearestNeighbors.getNeighbors(grupo.get(0).getIdUser());
                    int size = nn.size();
                    if (size == 0) {
                        flag = 1;
                    }
                    OntModel[] user = new OntModel[size];
                    int count = 0;
                    while (size > count) {
                        user[count] = UserOntologyManager.getUserModel(Integer.parseInt(nn.get(count)), conf);
                        count++;
                    }

                    Iterator<Calificacion> ite2 = grupo.iterator();

                    //recorro las peliculas a las que voy a comparar la calificacion real con la predicha
                    while (ite2.hasNext()) {
                        Calificacion cal = ite2.next();
                        //obtengo el id de la pelicula en IMDb
                        String IMDbMovieID = UserOntologyManager.getMovieID(cal.getIdMovie(), conf.getDBMOVIES());
                        //obtengo la instancia de la pelicula en la ontologia
                        Individual movie = movies.getIndividual(conf.getNS() + IMDbMovieID);
//                        System.err.println(user[0].size()+" "+movies.getOntResource(conf.getNS() + IMDbMovieID));

                        if (movie != null) {

                            float inferedDOI = 0;
                            int generalcount = 0;
                            //obtengo sus generos, actores, directores, escritores
                            Property hasActor = movies.getProperty(conf.getNS() + "hasActor"); //propiedad que necesito								
                            Property hasDirector = movies.getProperty(conf.getNS() + "hasDirector");
                            Property hasWriter = movies.getProperty(conf.getNS() + "hasWriter");

                            //recorro las propiedades y obtengo las instancias relacionadas
                            float actorsDOI = 0;
                            float directorsDOI = 0;
                            float writerDOI = 0;
                            float genresDOI = 0;
                            for (int i = 0; i < size; i++) {
                                Individual movieU = user[i].getIndividual(conf.getNS() + IMDbMovieID);
//                                 if(movieU==null){
                                OntModel aux = movie.getOntModel();
                                user[i].add(aux);
//                                 }
//                        System.err.println(user[0].size()+" "+aux.size());
//                             aux.write(System.out);
//                                float actorsDOIaux = doiPropierty(user[i], movie, hasActor);
//                                float directorsDOIaux = doiPropierty(user[i], movie, hasDirector);
//                                float writerDOIaux = doiPropierty(user[i], movie, hasWriter);
                                float genresDOIaux = doiGenres(user[i], movie, grupo.get(0).getIdUser(), conf, true);

//                                if (actorsDOIaux != 0) {
//                                    generalcount++;
//                                    actorsDOI=actorsDOI+actorsDOIaux;
//                                }
//                                if (directorsDOIaux != 0) {
//                                    generalcount++;
//                                    directorsDOI=directorsDOI+directorsDOIaux;
//                                }
//                                if (writerDOIaux != 0) {
//                                    generalcount++;
//                                    writerDOI=writerDOIaux+writerDOI;
//                                }
                                if (genresDOIaux != 0) {
                                    generalcount++;
                                    genresDOI = genresDOI + genresDOIaux;
//                                    System.err.println(genresDOIaux+"    "+"    "+user[i].size());
                                }
//                                 System.err.println(actorsDOIaux + "   " + directorsDOIaux + "   " + writerDOIaux + "   " + genresDOIaux);
//                                 System.err.println(actorsDOI + "   " + directorsDOI + "   " + writerDOI + "   " + genresDOI);
                            }

                            if (generalcount != 0) {
                                inferedDOI = (actorsDOI + directorsDOI + writerDOI + genresDOI) / generalcount;
                            }
                            //inferedDOI = ponderarConRantingIMDb(movies, movie, inferedDOI, conf);
                            //guardo el DOI predicho en el archivo de salida
                            String linea = cal.getIdUser() + "," + cal.getIdMovie() + "," + inferedDOI + "," + cal.getRating();
                            if (flag == 0) {
                                error = error + Math.abs(inferedDOI - (int) cal.getRating());
                                Uerror = Uerror + Math.abs(inferedDOI - (int) cal.getRating());
                                nratings = nratings + 1;
                                Unratings = Unratings + 1;
                                //                            b1.write(linea+"     "+(Math.abs(inferedDOI - (int) cal.getRating()))/5);
                                //                            b1.newLine();
                                //                            b1.flush();
                            }
                        } else {
                            System.out.println("no existe la pelicula " + IMDbMovieID + " en la ontologia");
                        }
                    }

                    if (flag == 0) {
                        b1.write(grupo.get(0).getIdUser() + ":" + size + ":" + (Uerror / (5 * Unratings)));
                        b1.newLine();
                        b1.flush();
                    } else {
                        b1.write("no tiene vecinos el usuario :" + grupo.get(0).getIdUser() + "  ");
                        b1.newLine();
                        b1.flush();
                    }
                }

            }

            b1.write("el error " + (error / (5 * nratings)));
            b1.newLine();
            b1.flush();

            System.err.println("el error total es: " + (error / nratings));
            b1.close();
        } catch (NoExisteLaOntologiaException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSePudoPersistirElModeloException e) {
            e.printStackTrace();
        }

    }

    /**
     * Metodo que pondera el DOI predicho con el rating otorgado por IMDb
     *
     * @param user perfil-ontologia del usuario
     * @param movie instancia de la peluicula en la ontologia
     * @param doi el DOI predicho de esta pelicula y para este usuario
     * @param conf configuracion del sistema
     */
    private static float ponderarConRantingIMDb(OntModel user, Individual movie, float doi, Configuration conf) {
        DatatypeProperty hasRanking = user.getDatatypeProperty(conf.getNS() + "hasRanking");
        RDFNode prop = movie.getPropertyValue(hasRanking);
        if (prop != null) {
            float rating = new Float(prop.asLiteral().getString()).floatValue();
            return ((rating / 2) + doi) / 2;
        }
        return doi;
    }

    private static double ponderarConRantingIMDb2(OntModel user, Individual movie, double doi, Configuration conf) {
        DatatypeProperty hasRanking = user.getDatatypeProperty(conf.getNS() + "hasRanking");
        RDFNode prop = movie.getPropertyValue(hasRanking);
        if (prop != null) {
            float rating = new Float(prop.asLiteral().getString()).floatValue();

            if (rating >= 9) {
                return (doi + 5) / 2;
            } else if (rating <= 3) {
                return (doi + 1) / 2;
            } else if (rating > 3 && rating < 6) {
                return ((rating / 2) + doi) / 2;
            } else {
                return doi;
            }

        }
        return doi;
    }

    private static float doiGenres(OntModel userOnt, Individual movie, int user, Configuration conf, boolean usuario) {
        float doi = 0;
        //obtengo las secuencias de propiedades relevantes para el usuario
        ArrayList<PropertySequence> sequence = Filtrado.filtradoDePropiedades(userOnt, movie);
        doi = Inferencia.inferedDOI(userOnt, sequence, movie, user, conf, usuario);
        return doi;
    }

    private static float doiPropierty(OntModel user, Individual movie, Property p) {
        float doi = 0;
        int count = 0;
        StmtIterator k = movie.listProperties(p);
        //recorro las propiedades y obtengo las instancias relacionadas
        while (k.hasNext()) {
            Statement stat = k.next();
            if (stat != null) {
                Resource res = stat.getResource(); //obtengo la instancia asociada a la pelicula
                Individual instancia = user.getIndividual(res.getURI());
                if (instancia != null) {
                    float instdoi = Filtrado.getDOI(instancia, user);
                    if (instdoi != 0) {
                        doi = doi + instdoi;
                        count++;
                    }
                }
            }
        }

        float propertyDOI = 0;
        if (count != 0) {
            return propertyDOI = doi / count;
        } else {
            return 0;
        }
    }

    private static ArrayList<String> top(ArrayList<String> result, int size) {
        int count = result.size();
        for (int i = 0; i < count; i++) {

            float cal = 0, cal2 = 0;
            String campos[] = null;
            campos = result.get(i).split(",");
            cal = Float.parseFloat(campos[2]);
            for (int j = 0; j < count; j++) {
                cal2 = 0;
                String campos2[] = null;
                campos2 = result.get(j).split(",");
                cal2 = Float.parseFloat(campos2[2]);
                if (cal < cal2) {
                    String aux = null;
                    aux = result.get(i);
                    result.set(i, result.get(j));
                    result.set(j, aux);
//                                if(campos[1].contains("8"))
//                                    System.err.println(campos[1]);
                }
            }
        }
        return result;
    }

    public static int buscaEstereotipo(int idUser) {
        /*UserManager um = new UserManager();
         User usuario = um.findId(idUser);
         if (usuario != null) {
         if (usuario.getEdad() < 18 && usuario.getSexo().equals("M")) {
         return 1;
         } else if (usuario.getEdad() < 18 && usuario.getSexo().equals("F")) {
         return 2;
         } else if (usuario.getEdad() >= 18 && usuario.getEdad() < 25 && usuario.getSexo().equals("M")) {
         return 3;
         } else if (usuario.getEdad() >= 18 && usuario.getEdad() < 25 && usuario.getSexo().equals("F")) {
         return 4;
         } else if (usuario.getEdad() >= 25 && usuario.getEdad() < 35 && usuario.getSexo().equals("M")) {
         return 5;
         } else if (usuario.getEdad() >= 25 && usuario.getEdad() < 35 && usuario.getSexo().equals("F")) {
         return 6;
         } else if (usuario.getEdad() >= 35 && usuario.getEdad() < 44 && usuario.getSexo().equals("M")) {
         return 7;
         } else if (usuario.getEdad() >= 35 && usuario.getEdad() < 45 && usuario.getSexo().equals("F")) {
         return 8;
         } else if (usuario.getEdad() >= 45 && usuario.getEdad() < 50 && usuario.getSexo().equals("M")) {
         return 9;
         } else if (usuario.getEdad() >= 45 && usuario.getEdad() < 50 && usuario.getSexo().equals("F")) {
         return 10;
         } else if (usuario.getEdad() >= 50 && usuario.getEdad() < 56 && usuario.getSexo().equals("M")) {
         return 11;
         } else if (usuario.getEdad() >= 50 && usuario.getEdad() < 56 && usuario.getSexo().equals("F")) {
         return 12;
         } else if (usuario.getEdad() >= 56 && usuario.getSexo().equals("M")) {
         return 13;
         } else if (usuario.getEdad() >= 56 && usuario.getSexo().equals("F")) {
         return 14;
         }
         }*/
        return 0;

    }

}
